import _ from "lodash"
import { fetchLotSize } from "../moex/fetch-lot-size"
import { fetchPrice } from "../moex/fetch-price"

export interface MoexAsset {
    code: string,
    count: number,
    freeFloat: number,
    weight: number
  }
export interface PortfileAsset {
    code: string
    weight: number
    lotSize: number
    price: number
    count: number
}

/**
 * Функция `getPortfolio` используется для получения списка активов портфеля на основе данных индекса IMOEX
 * и общей суммы капитала.
 * 
 * @param {MoexAsset[]} data - Данные о составе индекса IMOEX.
 * @param {number} capital - Общая сумма капитала, которую необходимо распределить по активам портфеля.
 * @returns {Promise<PortfileAsset[]>} - Список активов портфеля.
 * 
 * @example
 * ```typescript
 * // Пример использования функции `getPortfolio`
 * const data: MoexAsset[] = [
 *   { code: 'A', weight: 0.2, count: 100 freeFloat: 0.5 },
 *   { code: 'B', weight: 0.3, count: 200, freeFloat: 0.6 },
 *   { code: 'C', weight: 0.5, count: 300, freeFloat: 0.7 }
 * ];
 * const capital = 1000;
 * 
 * const portfolio = await getPortfolio(data, capital);
 * 
 * console.log(portfolio);
 * //вод: список активов портфеля
 * ```
 */
export async function getPortfolio(data: MoexAsset[], capital: number): Promise<PortfileAsset[]> {
    const index = _.reverse(_.sortBy(data, row => row.weight))
    let out: PortfileAsset[] = []

    for(let i=0; i< index.length; i++) {
        const asset = index[i]
        const lotSize = await fetchLotSize(asset.code)
        const price = await fetchPrice(asset.code)
        if (!price) {
            throw new Error(`Не смог загрузить цену для ${asset.code}`)
        }

        const a: PortfileAsset = {
            code: asset.code,
            lotSize,
            price,
            weight: asset.weight,
            count: 0
        }
        const next = rebalance([a, ...out], capital)
        if (!validate(next)) {
            return _.sortBy(out, a => -1 * a.weight)
        } else {
            out = next
        }
    }

    return _.sortBy(out, a => -1 * a.weight)
}



function validate(portfolio: PortfileAsset[]): boolean {
    for(let i=0; i<portfolio.length; i++) {
        const asset = portfolio[i]
        if (asset.count <= 0) return false
    }
    return true
}

function rebalance(assets: PortfileAsset[], capital: number): PortfileAsset[] {
    const sum = _.sumBy(assets, a => a.weight)
    return _.map(assets, a => ({
        ...a, 
        count: Math.floor((a.weight/sum * capital) / a.price / a.lotSize) * a.lotSize
    }))
}